// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Logger from './Logger';

const FRAME_TYPE_MAP = {
    2: 'Audio',
    3: 'Video',
    8: 'HeartBeat',
    7: 'CmdControl',
    9: 'Orientation',
    14: 'KeyboardInput',
    60: 'PhoneControl',
    21: 'Camera',
    22: 'MicroPhone',
    23: 'Sensor'
};
const INVALID_FRAME_TYPE = 'Invalid';
// 限制数据包缓存的长度，避免过多占用资源
const MAX_PKG_NUMBER = 300;
const PACKAGE_HEADER_LENGTH = 8;

class FrameParser {
    constructor(supportAudio) {
        this.pkgList = {
            'Audio': [],
            'Video': [],
            'HeartBeat': [],
            'CmdControl': [],
            'Orientation': [],
            'KeyboardInput': [],
            'PhoneControl': [],
            'Camera': [],
            'MicroPhone': [],
            'Channel':[],
            'Sensor': []
        };
        this.lastBuf = null;
        // 完整数据包length，含header
        this.completePkgLen = 0;
        this.supportAudio = supportAudio;
    }

    getSizeFromPackage(typeBuf, pkgStart) {
        pkgStart = pkgStart || 0;
        if (typeBuf.length < pkgStart + PACKAGE_HEADER_LENGTH) {
            Logger.debug('The package is invalid.');
            return 0;
        }
        
        return (typeBuf[pkgStart + 4] << 24) | (typeBuf[pkgStart + 5] << 16) | (typeBuf[pkgStart + 6] << 8) | typeBuf[pkgStart + 7];
    }

    getTypeFromPackage(typeBuf, pkgStart) {
        pkgStart = pkgStart || 0;
        if (typeBuf.length < pkgStart + PACKAGE_HEADER_LENGTH) {
            Logger.debug('The package is invalid.');
            return INVALID_FRAME_TYPE;
        }

        return FRAME_TYPE_MAP[typeBuf[pkgStart + 3]] || INVALID_FRAME_TYPE;
    }

    getSubTypeBuffer(typeBuf, start, end) {
        end = end || typeBuf.length;
        const subBuf = typeBuf.subarray(start, end);
        const newBuf = new Uint8Array(subBuf.length);
        newBuf.set(subBuf);
        return newBuf;
    }

    readPackage(recvdBuf) {
        if (!recvdBuf || recvdBuf.byteLength < 1) {
            return;
        }

        // 已经接收到的数据（包含本次和之前数据包剩下的）
        let allDataBuf = null;
        let recvdTypeBuf = new Uint8Array(recvdBuf);
        if (this.lastBuf) {
            allDataBuf = new Uint8Array(this.lastBuf.length + recvdBuf.byteLength);
            allDataBuf.set(this.lastBuf);
            allDataBuf.set(recvdTypeBuf, this.lastBuf.length);
        } else {
            // 忽略心跳响应包
            const pkgType = this.getTypeFromPackage(recvdTypeBuf);
            if (pkgType === INVALID_FRAME_TYPE || (!this.supportAudio && pkgType === FRAME_TYPE_MAP[2] /* Audio */)) {
                recvdTypeBuf = null;
                return;
            }

            allDataBuf = recvdTypeBuf;
        }
        
        // 需要的组成一整包的数据，包含header
        if (!this.completePkgLen) {
            this.completePkgLen = this.getSizeFromPackage(allDataBuf) + PACKAGE_HEADER_LENGTH;
        }

        // 已有数据和需要的数据length比较
        if (allDataBuf.length === this.completePkgLen) {
            let type = this.getTypeFromPackage(allDataBuf);
            this.pushPackage(type, this.getSubTypeBuffer(allDataBuf, PACKAGE_HEADER_LENGTH));
            this.lastBuf = null;
            this.completePkgLen = 0;
        } else if (allDataBuf.length < this.completePkgLen) {
            this.lastBuf = allDataBuf;
        } else {
            let pkgStart = 0;
            let pkgLen = 0;
            const allDataLen = allDataBuf.length;
            while (allDataLen - pkgStart >= PACKAGE_HEADER_LENGTH) {
                pkgLen = this.getSizeFromPackage(allDataBuf, pkgStart) + PACKAGE_HEADER_LENGTH;
                if (allDataLen - pkgStart >= pkgLen) {
                    let type = this.getTypeFromPackage(allDataBuf, pkgStart);
                    this.pushPackage(type, this.getSubTypeBuffer(allDataBuf, pkgStart + PACKAGE_HEADER_LENGTH, pkgStart + pkgLen));
                    pkgStart += pkgLen;
                } else {
                    break;
                }
            }

            // 仍剩下不完整包的数据，存储至lastBuf
            if (allDataLen > pkgStart) {
                this.lastBuf = this.getSubTypeBuffer(allDataBuf, pkgStart);
            }
            
            this.completePkgLen = 0;
        }
    }

    pushPackage(type, pkg) {
        if (!this.pkgList[type]) {
            return;
        }

        if (this.pkgList[type].length >= MAX_PKG_NUMBER) {
            this.pkgList[type] = [];
        }

        this.pkgList[type].push(pkg);
    }

    shiftPackage(type) {
        return this.pkgList[type] && this.pkgList[type].shift();
    }

    clearPackageCache(type) {
        this.pkgList[type] && (this.pkgList[type] = []);
    }

    getPackageCacheNum(type) {
        return this.pkgList[type] && this.pkgList[type].length;
    }
}

export default FrameParser;
